package download

import (
	"fmt"
	"github.com/Exleryz/gorequest"
	"github.com/Exleryz/m3u8/constant"
	"github.com/Exleryz/m3u8/internal/m3u8/parser"
	"github.com/Exleryz/m3u8/util"
	"log"
	"math/rand"
	"os"
	"time"
)

// 部分 ts文件，下载完需要key解密

type TsDownload struct {
}

func (td *TsDownload) Download(info *parser.M3U8Info) {
	routineCount := make(chan struct{}, constant.PoolCount)
	f := make(chan struct{}, 10)

	for i := range info.TsList {
		//var disturbance = time.Duration(rand.Intn(1000))
		time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
		item := info.TsList[i]

		routineCount <- struct{}{}

		go func(tsInfo parser.TsInfo) {
			download(*info, tsInfo, 0)

			<-routineCount
			f <- struct{}{}
		}(item)
	}

	success := 0
	for success != len(info.TsList) {
		select {
		case <-f:
			success++
		}
	}
}

func download(info parser.M3U8Info, tsInfo parser.TsInfo, retry int) {
	defer func() {
		if err := recover(); err != nil {
			log.Println("retry", info.DirName, tsInfo.TsUrl, tsInfo.Index, retry, err)
			// 重试逻辑
			if retry < 50 {
				retry++

				// retry 秒 + x 毫秒(x>=500)
				var n = time.Duration(retry*1000 + rand.Intn(500) + 500)
				time.Sleep(n * time.Millisecond)

				download(info, tsInfo, retry)
			}
		}
	}()

	if retry == 0 {
		fmt.Println(tsInfo.TsUrl, tsInfo.Index, "start")
	} else {
		fmt.Println(tsInfo.TsUrl, tsInfo.Index, "restart")
	}

	_, body, errs := util.NewRequest(gorequest.New().Get(tsInfo.TsUrl)).
		EndBytes()
	if errs != nil {
		fmt.Println(errs)
		panic(errs)
	}

	create, err := os.Create(fmt.Sprintf("%s/%d.ts", info.DirName, tsInfo.Index))
	if err != nil {
		fmt.Println(err)
		return
	}
	defer create.Close()

	fmt.Println(len(body))

	if info.Key != nil {
		fmt.Println(tsInfo.Index, info.Key.Method, "Decrypt, start")
		body, err = util.CBCDecrypt(body, info.Key.KeyInfo, info.Key.IV, util.PKCS7)
		if err != nil {
			fmt.Println(err)
			fmt.Println(tsInfo.Index, info.Key.Method, "Decrypt, error use origin")
		}
		fmt.Println(tsInfo.Index, info.Key.Method, "Decrypt, end")
	}
	create.Write(body)

	fmt.Println(tsInfo.TsUrl, tsInfo.Index, "end")
}
